package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserInfo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.UUID;

/**
 *
 */
@Component
@Aspect
public class TsLoginAspect {
    @Autowired
    private RedisTemplate redisTemplate;

    //@annotation(org.springframework.transaction.annotation.Transactional)
    //环绕通知：切注解 TsLogin
    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(tsLogin)")
    public Object doTsLoginAspect(ProceedingJoinPoint point,TsLogin tsLogin) throws Throwable {
        Object obj = new Object();
        //如何判断用户是否登录
        /**
         * 1.需要通过token 来判断用户是否登录
         *   如果请求头中有token，则登录！否则提示登录
         */
        //获取请求头中的token
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        //获取request对象
        HttpServletRequest request = servletRequestAttributes.getRequest();
        //获取到response对象
        //HttpServletResponse response = servletRequestAttributes.getResponse();
        String token = request.getHeader("token");
        //判断注解的属性
        if (tsLogin.required()) {
            if (StringUtils.isEmpty(token)) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //根据token 获取用户信息；
            String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
            UserInfo userInfo  = (UserInfo) this.redisTemplate.opsForValue().get(userLoginKey);
            //判断用户是否为空
            if (null == userInfo){
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
        }

        try { // 说明此处不需要登录
            if (!StringUtils.isEmpty(token)) {
                // 从缓存中获取数据
                String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
                UserInfo userInfo = (UserInfo) this.redisTemplate.opsForValue().get(userLoginKey);
                if (null != userInfo) {
                    //存储用户id 到本地线程
                    AuthContextHolder.setUserId(userInfo.getId());

                }
            }
            return point.proceed();
        }catch (Throwable e){
            throw new RuntimeException(e);
        } finally {
            //释放本地内存 防止 ThreadLocal 内存泄露
            AuthContextHolder.removeUserId();
        }
    }
}
